package cn.zhentao.service.impl;

import cn.zhentao.service.OcrService;
import com.alibaba.fastjson2.JSON;
import com.aliyun.ocr_api20210707.Client;
import com.aliyun.ocr_api20210707.models.*;
import com.aliyun.teautil.models.RuntimeOptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * OCR图片识别服务实现类
 * 
 * @author zhentao
 */
@Service
@Slf4j
@ConditionalOnProperty(name = "ocr.mock.enabled", havingValue = "false", matchIfMissing = true)
public class OcrServiceImpl implements OcrService {
    
    @Autowired
    private Client ocrClient;
    
    @Override
    public String recognizeGeneralText(String imageUrl) {
        try {
            RecognizeGeneralRequest request = new RecognizeGeneralRequest();
            request.setUrl(imageUrl);

            RuntimeOptions runtime = new RuntimeOptions();
            RecognizeGeneralResponse response = ocrClient.recognizeGeneralWithOptions(request, runtime);
            return JSON.toJSONString(response.getBody());
        } catch (Exception e) {
            log.error("通用文字识别失败: {}", e.getMessage(), e);
            throw new RuntimeException("通用文字识别失败: " + e.getMessage());
        }
    }
    
    @Override
    public String recognizeGeneralText(InputStream inputStream, String fileName) {
        try {
            log.info("开始识别图片文字，文件名: {}", fileName);

            // 将输入流转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
            byte[] imageBytes = outputStream.toByteArray();

            log.info("图片数据大小: {} bytes", imageBytes.length);

            // 创建请求对象并设置图片数据
            RecognizeGeneralRequest request = new RecognizeGeneralRequest();
            request.setBody(new ByteArrayInputStream(imageBytes));

            // 设置运行时选项
            RuntimeOptions runtime = new RuntimeOptions();
            runtime.setConnectTimeout(30000); // 30秒连接超时
            runtime.setReadTimeout(60000);    // 60秒读取超时

            log.info("正在调用阿里云OCR API...");
            RecognizeGeneralResponse response = ocrClient.recognizeGeneralWithOptions(request, runtime);

            if (response != null && response.getBody() != null) {
                log.info("OCR识别成功，返回结果");
                return JSON.toJSONString(response.getBody());
            } else {
                log.warn("OCR识别返回空结果");
                return createEmptyResult("识别结果为空");
            }

        } catch (Exception e) {
            log.error("通用文字识别失败: {}", e.getMessage(), e);

            // 根据不同的异常类型提供更详细的错误信息
            String errorMessage = getDetailedErrorMessage(e);
            throw new RuntimeException("通用文字识别失败: " + errorMessage);
        }
    }

    /**
     * 获取详细的错误信息
     */
    private String getDetailedErrorMessage(Exception e) {
        String message = e.getMessage();
        if (message == null) {
            message = e.getClass().getSimpleName();
        }

        if (message.contains("UnknownHostException") || message.contains("不知道这样的主机")) {
            return "无法连接到阿里云OCR服务，请检查网络连接和DNS设置。建议：1)检查网络连接 2)更换DNS服务器 3)检查防火墙设置";
        } else if (message.contains("ConnectTimeoutException") || message.contains("timeout")) {
            return "连接超时，请检查网络状况或稍后重试";
        } else if (message.contains("SSL") || message.contains("certificate")) {
            return "SSL证书验证失败，可能是网络代理或证书问题";
        } else if (message.contains("403") || message.contains("Forbidden")) {
            return "访问被拒绝，请检查阿里云AccessKey和Secret是否正确";
        } else if (message.contains("401") || message.contains("Unauthorized")) {
            return "认证失败，请检查阿里云AccessKey和Secret是否有效";
        } else {
            return message;
        }
    }

    /**
     * 创建空结果
     */
    private String createEmptyResult(String reason) {
        Map<String, Object> result = new HashMap<>();
        result.put("success", false);
        result.put("message", reason);
        result.put("data", Map.of(
            "textBlocks", new ArrayList<>(),
            "fullText", "",
            "totalBlocks", 0
        ));
        return JSON.toJSONString(result);
    }
    
    @Override
    public String recognizeIdCard(String imageUrl, String side) {
        try {
            RecognizeIdcardRequest request = new RecognizeIdcardRequest();
            request.setUrl(imageUrl);
            // 注意：阿里云OCR SDK可能不支持setSide方法，这里只设置URL
            // 如果需要区分正反面，可能需要使用不同的API接口

            RuntimeOptions runtime = new RuntimeOptions();
            RecognizeIdcardResponse response = ocrClient.recognizeIdcardWithOptions(request, runtime);
            return JSON.toJSONString(response.getBody());
        } catch (Exception e) {
            log.error("身份证识别失败: {}", e.getMessage(), e);
            throw new RuntimeException("身份证识别失败: " + e.getMessage());
        }
    }
    
    @Override
    public String recognizeIdCard(InputStream inputStream, String fileName, String side) {
        try {
            // 将输入流转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
            byte[] imageBytes = outputStream.toByteArray();

            RecognizeIdcardRequest request = new RecognizeIdcardRequest();
            request.setBody(new ByteArrayInputStream(imageBytes));
            // 注意：阿里云OCR SDK可能不支持setSide方法，这里只设置图片数据
            // 如果需要区分正反面，可能需要使用不同的API接口

            RuntimeOptions runtime = new RuntimeOptions();
            RecognizeIdcardResponse response = ocrClient.recognizeIdcardWithOptions(request, runtime);
            return JSON.toJSONString(response.getBody());
        } catch (Exception e) {
            log.error("身份证识别失败: {}", e.getMessage(), e);
            throw new RuntimeException("身份证识别失败: " + e.getMessage());
        }
    }
    
    @Override
    public String recognizeBankCard(String imageUrl) {
        try {
            RecognizeBankCardRequest request = new RecognizeBankCardRequest();
            request.setUrl(imageUrl);

            RuntimeOptions runtime = new RuntimeOptions();
            RecognizeBankCardResponse response = ocrClient.recognizeBankCardWithOptions(request, runtime);
            return JSON.toJSONString(response.getBody());
        } catch (Exception e) {
            log.error("银行卡识别失败: {}", e.getMessage(), e);
            throw new RuntimeException("银行卡识别失败: " + e.getMessage());
        }
    }
    
    @Override
    public String recognizeBankCard(InputStream inputStream, String fileName) {
        try {
            // 将输入流转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
            byte[] imageBytes = outputStream.toByteArray();

            RecognizeBankCardRequest request = new RecognizeBankCardRequest();
            request.setBody(new ByteArrayInputStream(imageBytes));

            RuntimeOptions runtime = new RuntimeOptions();
            RecognizeBankCardResponse response = ocrClient.recognizeBankCardWithOptions(request, runtime);
            return JSON.toJSONString(response.getBody());
        } catch (Exception e) {
            log.error("银行卡识别失败: {}", e.getMessage(), e);
            throw new RuntimeException("银行卡识别失败: " + e.getMessage());
        }
    }
    
    @Override
    public String recognizeBusinessLicense(String imageUrl) {
        try {
            RecognizeBusinessLicenseRequest request = new RecognizeBusinessLicenseRequest();
            request.setUrl(imageUrl);

            RuntimeOptions runtime = new RuntimeOptions();
            RecognizeBusinessLicenseResponse response = ocrClient.recognizeBusinessLicenseWithOptions(request, runtime);
            return JSON.toJSONString(response.getBody());
        } catch (Exception e) {
            log.error("营业执照识别失败: {}", e.getMessage(), e);
            throw new RuntimeException("营业执照识别失败: " + e.getMessage());
        }
    }
    
    @Override
    public String recognizeBusinessLicense(InputStream inputStream, String fileName) {
        try {
            // 将输入流转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
            byte[] imageBytes = outputStream.toByteArray();

            RecognizeBusinessLicenseRequest request = new RecognizeBusinessLicenseRequest();
            request.setBody(new ByteArrayInputStream(imageBytes));

            RuntimeOptions runtime = new RuntimeOptions();
            RecognizeBusinessLicenseResponse response = ocrClient.recognizeBusinessLicenseWithOptions(request, runtime);
            return JSON.toJSONString(response.getBody());
        } catch (Exception e) {
            log.error("营业执照识别失败: {}", e.getMessage(), e);
            throw new RuntimeException("营业执照识别失败: " + e.getMessage());
        }
    }
    
    /**
     * 将输入流转换为Base64字符串
     * 
     * @param inputStream 输入流
     * @return Base64字符串
     * @throws IOException IO异常
     */
    private String convertToBase64(InputStream inputStream) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, length);
        }
        byte[] imageBytes = outputStream.toByteArray();
        return Base64.getEncoder().encodeToString(imageBytes);
    }
}
